import DelimiterNode from "./delimiter_node";
import { DelNode, EmphNode, MNode, ParagraphNode, StrongNode, TextNode } from "./mnodes";

export default class MarkdownParserLine {
  static textReg = /^[^*_~]+/m; // 普通文本

  private _offset: number;
  private _delimiter: DelimiterNode | null;
  private _line: string;
  private _mnode: MNode | null;

  constructor () {
    this._offset = 0;
    this._delimiter = null;
    this._line = '';
    this._mnode = null;
  }

  parse (line: string): MNode {
    this._offset = 0;
    this._delimiter = null;
    this._mnode = new ParagraphNode();
    this._line = line;

    this._parseLine();
    this._transNormal();

    return this._mnode;
  }

  // 匹配普通文本
  _match (reg: RegExp): string | null {
    const matched = reg.exec(this._line.slice(this._offset));
    if (matched) {
      this._offset += matched[0].length;
      return matched[0];
    } else {
      return null;
    }
  }

  // 从左往右逐字扫描转化
  _parseLine (): void {
    let char: string = '';
    while (char = this._line[this._offset]) {
      switch (char) {
        case '*':
        case '_':
        case '~':
          this._parseNormal(char);
        default:
          this._parseText();
      }
    }
  }

  _parseText (): void {
    const matchText: string | null = this._match(MarkdownParserLine.textReg);
    if (matchText) {
      this._mnode?.appendChild(new TextNode(matchText));
    }
  }

  _parseNormal (char: string): void {
    let count: number = 0;
    let startPos: number = this._offset;
    while (this._line[this._offset] === char) {
      count++;
      this._offset++;
    }
    const textNode: TextNode = new TextNode(this._line.substr(startPos, count));
    this._mnode?.appendChild(textNode);
    const delimiter: DelimiterNode = new DelimiterNode(char, count, textNode);
    if (this._delimiter) {
      this._delimiter.next = delimiter;
      delimiter.pre = this._delimiter;
    }
    this._delimiter = delimiter;
  }

  _transNormalOpener (closer: DelimiterNode): DelimiterNode | null {
    let opener: DelimiterNode | null = closer.pre;
    while (opener && opener != null) {
      if (opener.char === closer.char) {
        return opener;
      } else {
        opener = opener.pre;
      }
    }
    return null;
  }

  _transNormal() {
    let closer: DelimiterNode | null = this._delimiter;
    let opener: DelimiterNode | null = null;

    while (closer != null && closer.pre != null) {
      closer = closer.pre;
    }

    while (closer) {
      const char: string = closer.char;
      if (char === '*' || char === '_' || char === '~') {
          opener = this._transNormalOpener(closer);
          if (opener) {
              let usedCount = 0; // 记录消耗掉的标识符数量
              const openerNode: MNode = opener.mnode;
              const closerNode: MNode = closer.mnode;
              let transNode: MNode | null = null; // 根据标识符配对生成的节点
              
              if (char === '*' || char === '_') {
                  if (opener.currentCount >= 2 && closer.currentCount >= 2) {
                      transNode = new StrongNode();
                      usedCount = 2;
                  } else {
                      transNode = new EmphNode();
                      usedCount = 1;
                  }
              } else {
                  usedCount = 1;
                  transNode = new DelNode();
              }

              // 消耗掉的标识符
              opener.currentCount -= usedCount;
              openerNode.text = openerNode.text.slice(usedCount);

              closer.currentCount -= usedCount;
              closerNode.text = closerNode.text.slice(usedCount);

              // 把opener和closer之间的内容，包含到新节点中去
              let betweenNode: MNode | null = openerNode.next;
              let next;
              while (betweenNode && betweenNode !== closerNode) {
                  next = betweenNode.next;
                  // betweenNode.unlink();
                  transNode.appendChild(betweenNode);
                  betweenNode = next;
              }

              // 将失败转换后的节点，插入到节点树中去
              openerNode.insertAfter(transNode);
              // opener 和 closer 之间的其他分隔符将作为普通文本显示，没有机会去匹配转换了，因此从链表移除
              DelimiterNode.removeBetween(opener, closer);
              // 分隔符消耗后，剩余分隔符数量为0时，其对应的节点都没必要保留了
              if (opener.currentCount === 0) {
                  opener.remove();
                  openerNode.unlink();
              }

              if (closer.currentCount === 0) {
                  // closer 需要后移，用于后续继续匹配
                  const nextCloser = closer.next;
                  if (this._delimiter === closer) {
                      this._delimiter = closer.pre;
                  }
                  closer.remove();
                  closer = nextCloser;
                  closerNode.unlink();
              }
          } else {
              // 没有找到opener,则当前closer无法作为闭合标识符，后移closer
              closer = closer.next;
          }
      } else {
          closer = closer.next;
      }
    }
  }
}